//
// 跨平台定时器框架
// Created by kenny on 25-11-6.
//
#include "platform_timer.h"
#include <stdlib.h>

#ifdef _WIN32
#include <windows.h>

struct platform_timer_s {
    HANDLE stop_event;
    unsigned int interval_sec;
};

/**
 * 创建，初始化
 * @param interval_sec
 * @return
 */
static platform_timer_t* win_timer_create(unsigned int interval_sec)
{
    platform_timer_t* timer = malloc(sizeof(platform_timer_t));
    if (!timer) return NULL;

    timer->interval_sec = interval_sec;
    timer->stop_event = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (!timer->stop_event) {
        free(timer);
        return NULL;
    }
    return timer;
}

/**
 * 跑起
 * @param timer
 * @return
 */
static bool win_timer_start(platform_timer_t* timer)
{
    if (!timer) return false;
    ResetEvent(timer->stop_event);
    return true;
}

/**
 *
 * @param timer 停止
 * @return
 */
static bool win_timer_stop(platform_timer_t* timer)
{
    if (!timer) return false;
    SetEvent(timer->stop_event);
    return true;
}

/**
 *
 * @param timer 注销
 */
static void win_timer_destroy(platform_timer_t* timer)
{
    if (!timer) return;
    if (timer->stop_event) {
        CloseHandle(timer->stop_event);
    }
    free(timer);
}

/**
 * 等待
 * @param timer
 */
static void win_timer_wait(platform_timer_t* timer)
{
    if (!timer) return;
    WaitForSingleObject(timer->stop_event, timer->interval_sec * 1000);
}

static const platform_timer_ops_t win_timer_ops = {
    .create = win_timer_create,
    .start = win_timer_start,
    .stop = win_timer_stop,
    .destroy = win_timer_destroy,
    .wait = win_timer_wait
};

#else
#include <pthread.h>
#include <unistd.h>
#include <sys/time.h>

struct platform_timer_s {
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    bool stop_request;
    unsigned int interval_sec;
};

static platform_timer_t* unix_timer_create(unsigned int interval_sec)
{
    platform_timer_t* timer = malloc(sizeof(platform_timer_t));
    if (!timer) return NULL;

    timer->interval_sec = interval_sec;
    timer->stop_request = false;
    pthread_mutex_init(&timer->mutex, NULL);
    pthread_cond_init(&timer->cond, NULL);
    return timer;
}

static bool unix_timer_start(platform_timer_t* timer)
{
    if (!timer) return false;
    pthread_mutex_lock(&timer->mutex);
    timer->stop_request = false;
    pthread_mutex_unlock(&timer->mutex);
    return true;
}

static bool unix_timer_stop(platform_timer_t* timer)
{
    if (!timer) return false;
    pthread_mutex_lock(&timer->mutex);
    timer->stop_request = true;
    pthread_cond_signal(&timer->cond);
    pthread_mutex_unlock(&timer->mutex);
    return true;
}

static void unix_timer_destroy(platform_timer_t* timer)
{
    if (!timer) return;
    pthread_mutex_destroy(&timer->mutex);
    pthread_cond_destroy(&timer->cond);
    free(timer);
}

static void unix_timer_wait(platform_timer_t* timer)
{
    if (!timer) return;

    pthread_mutex_lock(&timer->mutex);
    if (!timer->stop_request) {
        struct timespec ts;
        struct timeval tv;

        gettimeofday(&tv, NULL);
        ts.tv_sec = tv.tv_sec + timer->interval_sec;
        ts.tv_nsec = tv.tv_usec * 1000;

        pthread_cond_timedwait(&timer->cond, &timer->mutex, &ts);
    }
    pthread_mutex_unlock(&timer->mutex);
}

static const platform_timer_ops_t unix_timer_ops = {
    .create = unix_timer_create,
    .start = unix_timer_start,
    .stop = unix_timer_stop,
    .destroy = unix_timer_destroy,
    .wait = unix_timer_wait
};

#endif

const platform_timer_ops_t* get_platform_timer_ops(void)
{
#ifdef _WIN32
    return &win_timer_ops;
#else
    return &unix_timer_ops;
#endif
}